集合初始化器

  第5章描述了如何使用如下语法,用值来初始化数组:

    int[] myIntArray = new int[5]{ 5, 7, 11, 2, 98 };

  这是一种合并实例化和初始化数组的简捷方式。集合初始化器只是把这个语法扩展到集合上:

    List<int> myIntCollection = new List<int> { 5, 7, 11, 2, 98 };

  通过合并对象和集合初始化器,就可以用简洁的代码配置集合了。下面的代码:

    List<Curry> curries = new List<Curry>();
    curries.Add(new Curry("Chicken", "Pathia", 6));
    curries.Add(new Curry("Vegetable", "Korma", 3));
    curries.Add(new Curry("Prawn", "Vindaloo", 9));

  可以用如下代码替换:

    List<Curry> curries = new List<Curry>
    {
        new Curry
        {
            MainIngredient = "Chicken",
            Style = "Pathia",
            Spiciness = 6
        },
        new Curry
        {
            MainIngredient = "Vegetable",
            Style = "Korma",
            Spiciness = 3
        },
        new Curry
        {
            MainIngredient = "Prawn",
            Style = "Vindaloo",
            Spiciness = 9
        }
    };

  这非常适合于主要用于数据表示的类型,因此,集合初始化器和本书后面介绍的LINQ技术一起使用时效果极佳。


  下面的示例说明了如何使用对象和集合初始化器。

    static void Main(string[] args)
    {
        Farm<Animal> farm = new Farm<Animal>
        {
            new Cow { Name = "Norris" },
            new Chicken { Name = "Rita" },
            new Chicken(),
            new SuperCow { Name = "Chesney" }
        };
        farm.MakeNoises();
        Console.ReadKey();
    }

    public class Farm<T> : IEnumerable<T> where T : Animal
    {
        public void Add(T animal)
        {
            animals.Add(animal);
        }
        ...
    }

  示例的说明

  这个示例合并了对象和集合初始化器,用一个步骤创建并填充了一个对象集合。它使用前面章节介绍的农场对象集合,但需要对用于这些类的初始化器做两处修改。

  首先,给派生于Animal基类的类删除构造函数。可以删除这些构造函数,是因为它们设置了动物的Name属性,而这里使用对象初始化器来完成。另外,还可以添加默认的构造函数。无论采用哪种方式,在使用默认的构造函数时,会根据基类中的默认构造函数来初始化Name属性,代码如下:

    public Animal()
    {
        name = "The animal with no name";
    }

  但是,对象初始化器与派生于Animal类的类一起使用时,初始化器设置的任何属性都在对象实例化后设置,因此在执行这个基类的构造函数之后设置。如果Name属性的值作为对象初始化器的一部分提供,这个值就会覆盖默认值。在示例代码中,为添加到集合中的所有项设置了Name属性,只有一项除外。

  其次,必须给Farm类添加Add()方法,否则会得到如下形式的一些列编译错误:

    'Ch14Ex01.Farm<Ch14Ex01.Animal>' does not contain a definition for 'Add'

  这个错误显示出了集合初始化器的部分底层功能。在后台,编译器为在集合初始化器中提供的每一项调用集合的Add()方法。Farm类通过Animals属性提供了一个Animal对象的集合。编译器猜不出这就是要通过Animals.Add()填充的属性,所以代码会失败。为更正这个问题,可以把Add()方法添加到类中,类通过对象初始化器进行初始化。

  还可以修改示例中的代码,为Animals属性提供一个嵌套的初始化器,如下所示:

    static void Main(string[] args)
    {
        Farm<Animal> farm = new Farm<Animal>
        {
            Animals = 
            {
                new Cow { Name = "Norris" },
                new Chicken { Name = "Rita" },
                new Chicken(),
                new SuperCow { Name = "Chesney" }
            }
        };
        farm.MakeNoises();
        Console.ReadKey();
    }

  有了此代码,就不需要为Farm类提供Add()方法了。这个技巧适用于包含多个集合的类。这种情况下,用包含类的Add()方法添加的集合没有其他方式。

🔚